﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Data.Objects.DataClasses;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Script.Serialization;

namespace Inovout.Cloud.DataStore.Web.Utility
{
    public class JsonUtility
    {
        /// <summary>
        /// 类对像转换成json格式
        /// </summary> 
        /// <returns></returns>
        public static string ToJson(object t)
        {
            var jss = new JavaScriptSerializer();
            jss.MaxJsonLength = int.MaxValue;
            string str = jss.Serialize(t);
            str = Regex.Replace(str, @"\\/Date\((\d+)\)\\/", match =>
            {
                DateTime dt = new DateTime(1970, 1, 1);
                dt = dt.AddMilliseconds(long.Parse(match.Groups[1].Value));
                dt = dt.ToLocalTime();
                return dt.ToString("yyyy-MM-dd HH:mm:ss");
            });

            return str;
        }

        /// <summary>
        /// json格式转换
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="strJson"></param>
        /// <returns></returns>
        public static T FromJson<T>(string strJson) where T : class
        {
            return new JavaScriptSerializer().Deserialize<T>(strJson);
        }

        public static string ConvertToJson<T>(T obj)
        {
            DataContractJsonSerializer ds = new DataContractJsonSerializer(typeof(T));
            using (MemoryStream ms = new MemoryStream())
            {
                ds.WriteObject(ms, obj);
                return Encoding.UTF8.GetString(ms.ToArray());
            }
        }

        public static T ConvertToObject<T>(string json)
        {
            DataContractJsonSerializer outDs = new DataContractJsonSerializer(typeof(T));
            using (MemoryStream outMs = new MemoryStream(Encoding.UTF8.GetBytes(json)))
            {
                return (T)outDs.ReadObject(outMs);
            }
        }

        public static string ListToJson<T>(string jsonName, IList<T> list)
        {
            StringBuilder Json = new StringBuilder();
            if (string.IsNullOrEmpty(jsonName))
                jsonName = list[0].GetType().Name;
            Json.Append("\"" + jsonName + "\":[");
            if (list.Count > 0)
            {
                for (int i = 0; i < list.Count; i++)
                {
                    T obj = Activator.CreateInstance<T>();
                    PropertyInfo[] pi = obj.GetType().GetProperties();
                    Json.Append("{");
                    for (int j = 0; j < pi.Length; j++)
                    {
                        Type type = pi[j].GetValue(list[i], null).GetType();
                        Json.Append("\"" + pi[j].Name.ToString() + "\":"
                            + StringFormat(pi[j].GetValue(list[i], null).ToString(), type));

                        if (j < pi.Length - 1)
                        {
                            Json.Append(",");
                        }
                    }
                    Json.Append("}");
                    if (i < list.Count - 1)
                    {
                        Json.Append(",");
                    }
                }
            }
            Json.Append("]");
            return Json.ToString();
        }

        /// <summary>
        /// 过滤特殊字符
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        private static string String2Json(String s)
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < s.Length; i++)
            {
                char c = s.ToCharArray()[i];
                switch (c)
                {
                    case '\"':
                        sb.Append("\\\""); break;
                    case '\\':
                        sb.Append("\\\\"); break;
                    case '/':
                        sb.Append("\\/"); break;
                    case '\b':
                        sb.Append("\\b"); break;
                    case '\f':
                        sb.Append("\\f"); break;
                    case '\n':
                        sb.Append("\\n"); break;
                    case '\r':
                        sb.Append("\\r"); break;
                    case '\t':
                        sb.Append("\\t"); break;
                    default:
                        sb.Append(c); break;
                }
            }
            return sb.ToString();
        }

        /// <summary> 
        /// 格式化字符型、日期型、布尔型、Guid型 
        /// </summary> 
        /// <param name="str"></param> 
        /// <param name="type"></param> 
        /// <returns></returns> 
        private static string StringFormat(string str, Type type)
        {
            if (type == typeof(string))
            {
                str = String2Json(str);
                str = "\"" + str + "\"";
            }
            else if (type == typeof(DateTime))
            {
                str = "\"" + Convert.ToDateTime(str).ToShortDateString() + "\"";
            }
            else if (type == typeof(bool))
            {
                str = str.ToLower();
            }
            else if (type == typeof(Guid))
            {
                str = "\"" + str + "\"";
            }

            if (str.Length == 0)
                str = "\"\"";

            return str;
        }


        public static Object Json2Obj(String json, Type t)
        {
            try
            {
                System.Runtime.Serialization.Json.DataContractJsonSerializer serializer =
                    new System.Runtime.Serialization.Json.DataContractJsonSerializer(t);
                using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(json)))
                {

                    return serializer.ReadObject(ms);
                }
            }
            catch
            {
                return null;
            }
        }

        /// <summary>
        /// 将JSON解析成DataSet只限标准的JSON数据
        /// 例如：Json＝{t1:[{name:'数据name',type:'数据type'}]} 
        /// 或 Json＝{t1:[{name:'数据name',type:'数据type'}],t2:[{id:'数据id',gx:'数据gx',val:'数据val'}]}
        /// </summary>
        /// <param name="Json">Json字符串</param>
        /// <returns>DataSet</returns>
        public static DataSet JsonToDataSet(string Json)
        {
            try
            {
                DataSet ds = new DataSet();
                JavaScriptSerializer JSS = new JavaScriptSerializer();


                object obj = JSS.DeserializeObject(Json);
                Dictionary<string, object> datajson = (Dictionary<string, object>)obj;


                foreach (var item in datajson)
                {
                    DataTable dt = new DataTable(item.Key);
                    object[] rows = (object[])item.Value;
                    foreach (var row in rows)
                    {
                        Dictionary<string, object> val = (Dictionary<string, object>)row;
                        DataRow dr = dt.NewRow();
                        foreach (KeyValuePair<string, object> sss in val)
                        {
                            if (!dt.Columns.Contains(sss.Key))
                            {
                                dt.Columns.Add(sss.Key.ToString());
                                dr[sss.Key] = sss.Value;
                            }
                            else
                                dr[sss.Key] = sss.Value;
                        }
                        dt.Rows.Add(dr);
                    }
                    ds.Tables.Add(dt);
                }
                return ds;
            }
            catch
            {
                return null;
            }
        }

        /// <summary> 
        /// DataSet转换为Json 
        /// </summary> 
        /// <param name="dataSet">DataSet对象</param> 
        /// <returns>Json字符串</returns> 
        public static string ToJson(DataSet dataSet)
        {
            string jsonString = "{";
            foreach (DataTable table in dataSet.Tables)
            {
                jsonString += "\"" + table.TableName + "\":" + ToJson(table) + ",";
            }
            jsonString = jsonString.TrimEnd(',');
            return jsonString + "}";
        }

        /// <summary> 
        /// Datatable转换为Json 
        /// </summary> 
        /// <param name="table">Datatable对象</param> 
        /// <returns>Json字符串</returns> 
        public static string ToJson(DataTable dt)
        {
            StringBuilder jsonString = new StringBuilder();

            if (dt.Rows.Count == 0)
            {
                jsonString.Append("[{}]");
                return jsonString.ToString();
            }

            jsonString.Append("[");
            DataRowCollection drc = dt.Rows;
            for (int i = 0; i < drc.Count; i++)
            {
                jsonString.Append("{");
                for (int j = 0; j < dt.Columns.Count; j++)
                {
                    string strKey = dt.Columns[j].ColumnName;
                    string strValue = drc[i][j].ToString();
                    Type type = dt.Columns[j].DataType;
                    jsonString.Append("\"" + strKey + "\":");
                    strValue = StringFormat(strValue, type);
                    if (j < dt.Columns.Count - 1)
                    {
                        jsonString.Append(strValue + ",");
                    }
                    else
                    {
                        jsonString.Append(strValue);
                    }
                }
                jsonString.Append("},");
            }
            jsonString.Remove(jsonString.Length - 1, 1);
            jsonString.Append("]");
            return jsonString.ToString();
        }

        public static Dictionary<string, object> DictionaryFromJson(string jsonText)
        {
            return FromJson<Dictionary<string, object>>(jsonText);
        }


        /// <summary>
        /// 转换实体信息为Json
        /// </summary>
        /// <param name="obj">实体对象</param>
        /// <param name="Include">获取子对象：使用，号分开</param>
        /// <returns></returns>
        public static String EntitiesToJson(Object obj, String Include)
        {
            Type type = obj.GetType();
            String sJosnString = "";
            StringBuilder TempStringJson = new StringBuilder();
            StringBuilder json = new StringBuilder();
            switch (type.Name)
            {
                case "ObjectQuery`1":
                    TempStringJson.Clear();
                    json.Append("[");
                    foreach (Object _obj in obj as IQueryable)
                    {
                        TempStringJson.Append(EntitiesToJson(_obj, Include, 0));
                        TempStringJson.Append(",");
                    }
                    sJosnString = TempStringJson.ToString();
                    json.Append(sJosnString.Substring(0, sJosnString.Length - 1));
                    json.Append("]");
                    break;
                case "MongoQueryable`1":
                    TempStringJson.Clear();
                    json.Append("[");
                    foreach (Object _obj in obj as IQueryable)
                    {
                        TempStringJson.Append(EntitiesToJson(_obj, Include, 0));
                        TempStringJson.Append(",");
                    }
                    sJosnString = TempStringJson.ToString();
                    json.Append(sJosnString.Substring(0, sJosnString.Length - 1));
                    json.Append("]");
                    break;
                case "List`1":
                    TempStringJson.Clear();
                    json.Append("[");
                    foreach (Object _obj in obj as IList)
                    {
                        TempStringJson.Append(EntitiesToJson(_obj, Include, 0));
                        TempStringJson.Append(",");
                    }
                    sJosnString = TempStringJson.ToString();
                    json.Append(sJosnString.Substring(0, sJosnString.Length - 1));
                    json.Append("]");
                    break;
                default:
                    json.Append(EntitiesToJson(obj, Include, 0));
                    break;
            }
            return json.ToString().Replace('/', '\"');//将“/"转换成双引号

        }
        /// <summary>
        /// 转换实体信息为Json
        /// </summary>
        /// <param name="obj">实体对象</param>
        /// <param name="Include">获取子对象：使用，号分开</param>
        /// <param name="Level">当前递归的层级</param>
        /// <returns></returns>
        private static String EntitiesToJson(Object obj, String Include, int Level)
        {
            if (obj == null) { return null; }
            StringBuilder TempStringJson = new StringBuilder();

            List<String> IncludeA = Include.Split(',').ToList<String>();

            //需要排除的属性类型
            List<String> ignoreEntityTypes = new List<String> { "EntityReference`1", "EntityState", "EntityKey", "EntitySetName" };
            //实体集合
            List<String> ListType = new List<String> { "EntityCollection`1" };
            //数据类型(非实体集合类型)
            List<String> EntitesType = new List<String> { "Binary", "Boolean", "DateTime", "DateTimeOffset", "Decimal", "Double", "Guid", "Int16", "Int32", "Int64", "Single", "String", "Time" };
            //未支持的数据类型
            List<String> NotType = new List<String> { "Byte", "SByte" };


            StringBuilder json = new StringBuilder();
            json.Append("{");
            Type type = obj.GetType();
            PropertyInfo[] propertyInfoList = type.GetProperties();

            string doubleQuote = "/";

            #region 迭代属性
            foreach (PropertyInfo _PropertyInfo in propertyInfoList)
            {
                #region 排除类型
                if (ignoreEntityTypes.Contains(_PropertyInfo.PropertyType.Name))
                {
                    continue;
                }
                #endregion

                var propertyName = _PropertyInfo.Name;
                var propertyType = _PropertyInfo.PropertyType;
                var propertyValue = _PropertyInfo.GetValue(obj, null);

                try
                {

                    #region 值=null
                    if (propertyValue == null)
                    {
                        json.Append(doubleQuote + propertyName + doubleQuote +
                                        ":" + "null");
                        json.Append(",");
                        continue;
                    }
                    #endregion

                    #region 非实体集合类型
                    if (EntitesType.Contains(propertyValue.GetType().Name))
                    {
                        try
                        {
                            TempStringJson.Clear();
                            TempStringJson.Append(doubleQuote + propertyName + doubleQuote +
                                        ":" + StringFormat(propertyValue, propertyType));
                            TempStringJson.Append(",");

                            json.Append(TempStringJson);
                            continue;
                        }
                        catch (Exception Err)
                        {
                            throw Err;
                        }

                    }
                    #endregion

                    #region 非Include对象
                    if (!IncludeA.Contains(propertyName))
                    {
                        json.Append(doubleQuote + propertyName + doubleQuote +
                                        ":" + "null");
                        json.Append(",");
                        continue;
                    }
                    #endregion

                    #region 实体集合类型
                    if (ListType.Contains(propertyValue.GetType().Name) && Level == 0)
                    {
                        try
                        {
                            TempStringJson.Clear();

                            bool IsNull = true;
                            //用来判断集合是否为空，待改善的方法
                            foreach (Object p in (IRelatedEnd)propertyValue)
                            {
                                IsNull = false;
                                break;
                            }

                            if (IsNull)
                            {
                                TempStringJson.Append(doubleQuote + propertyName + doubleQuote +
                                                ":" + "null");
                                TempStringJson.Append(",");
                                continue;
                            }

                            StringBuilder ListJosnString = new StringBuilder();
                            json.Append(doubleQuote + propertyName + doubleQuote + ":[");
                            foreach (Object p in (IRelatedEnd)propertyValue)
                            {
                                String Child = EntitiesToJson(p, Include, 1);
                                ListJosnString.Append(Child);
                                ListJosnString.Append(",");
                            }
                            String sListJosnString = ListJosnString.ToString();
                            TempStringJson.Append(sListJosnString.Substring(0, sListJosnString.Length - 1));
                            TempStringJson.Append("]");
                            TempStringJson.Append(",");


                            json.Append(TempStringJson);
                            continue;
                        }
                        catch (Exception Err)
                        {
                            throw Err;
                        }
                    }
                    #endregion

                    #region 其他类型[应该只剩下实体对象了],有可能有没有考虑到的情况！
                    try
                    {
                        TempStringJson.Clear();
                        TempStringJson.Append(doubleQuote + propertyName + doubleQuote +
                                        ":" + EntitiesToJson(propertyValue, Include, 1));
                        TempStringJson.Append(",");


                        json.Append(TempStringJson);
                        continue;
                    }
                    catch (Exception Err)
                    {
                        throw Err;
                    }
                    #endregion
                }
                catch (Exception Err)
                {
                    json.Append(doubleQuote + propertyName + doubleQuote +
                                    ":" + "null");
                    json.Append(",");
                    continue;
                }

            }
            #endregion

            String sJosnString = json.ToString();
            return sJosnString.Substring(0, sJosnString.Length - 1) + "}";

        }


        /// <summary>
        /// 将datetime转换成js格式
        /// </summary>
        /// <param name="dt"></param>
        /// <returns></returns>
        private static double UnixTicks(DateTime dt)
        {
            DateTime d1 = new DateTime(1970, 1, 1);
            DateTime d2 = dt.ToUniversalTime();
            TimeSpan ts = new TimeSpan(d2.Ticks - d1.Ticks);
            return ts.TotalMilliseconds;
        }

        private static string StringFormat(object val, Type type)
        {
            string str = val.ToString();
            if (type == typeof(string))
            {
                // str = String2Json(str);
                str = "/" + str + "/";
            }
            else if (type == typeof(DateTime) || Nullable.GetUnderlyingType(type) == typeof(DateTime))
            {
                //str = Convert.ToString(UnixTicks(Convert.ToDateTime(val)));
                //str="\\/Date("+str+")\\/";
                str = "/" + str + "/";
            }
            else if (type == typeof(bool))
            {
                str = str.ToLower();
            }
            return str;
        }

    }
}